
// PY32DfuToolDlg.cpp : implementation file
//

#include "pch.h"
#include "framework.h"
#include "PY32DfuTool.h"
#include "PY32DfuToolDlg.h"
#include "afxdialogex.h"
//#include "py_program_protocol.h"
#include "MemoryFile.h"
#include "OptionBytesDlg.h"
#include "CSetAddrSizeDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

void CPY32DfuToolDlg::SetStructData(uint32_t mcu_pid)
{
	if (m_wPID == mcu_pid) {
		return;
	}
	m_wPID = mcu_pid;

	memset(FILE_InitStruct.OPTION_BYTES, 0xFF, sizeof(FILE_InitStruct.OPTION_BYTES));

	switch (mcu_pid)
	{
	case 0x0063:
	case 0x0448:
		//_tcscpy_s((TCHAR*)(CHIP_InitStruct.SERIES), 0x20, _T("PY32F072xx"));
		//_tcscpy_s((TCHAR*)(CHIP_InitStruct.NAME), 0x20, _T("PY32F072xBT6"));
		CHIP_InitStruct.FLASH_SIZE = 0x00020000;
		CHIP_InitStruct.PAGE_SIZE = 0x00000100;
		CHIP_InitStruct.SECTOR_SIZE = 0x00002000;
		CHIP_InitStruct.SYSTEM_ADDR = 0x1FFF0000;
		CHIP_InitStruct.SYSTEM_SIZE = 0x00003000;
		CHIP_InitStruct.UID_ADDR = 0x1FFF3000;
		CHIP_InitStruct.UID_SIZE = 0x00000100;
		CHIP_InitStruct.OPTION_ADDR = 0x1FFF3100;
		CHIP_InitStruct.OPTION_SIZE = 0x00000020;
		CHIP_InitStruct.FLASHSIZE_ADDR = 0x1FFF33F8;
		CHIP_InitStruct.RAM_SIZE = 0x00004000;
		M32(&FILE_InitStruct.OPTION_BYTES[0x00]) = 0x2755D8AA;
		M32(&FILE_InitStruct.OPTION_BYTES[0x08]) = 0xFFE0001F;
		M32(&FILE_InitStruct.OPTION_BYTES[0x18]) = 0x0000FFFF;
		break;
	case 0x0100:
	case 0x0413:
		//_tcscpy_s((TCHAR*)(CHIP_InitStruct.SERIES), 0x20, _T("PY32F403xx"));
		//_tcscpy_s((TCHAR*)(CHIP_InitStruct.NAME), 0x20, _T("PY32F403xDT6"));
		CHIP_InitStruct.FLASH_SIZE = 0x00060000;
		CHIP_InitStruct.PAGE_SIZE = 0x00000100;
		CHIP_InitStruct.SECTOR_SIZE = 0x00000800;
		CHIP_InitStruct.SYSTEM_ADDR = 0x1FFF0000;
		CHIP_InitStruct.SYSTEM_SIZE = 0x00005000;
		CHIP_InitStruct.UID_ADDR = 0x1FFF5800;
		CHIP_InitStruct.UID_SIZE = 0x00000080;
		CHIP_InitStruct.OPTION_ADDR = 0x1FFF5000;
		CHIP_InitStruct.OPTION_SIZE = 0x00000010;
		CHIP_InitStruct.FLASHSIZE_ADDR = 0x1FFF5700;
		CHIP_InitStruct.RAM_SIZE = 0x00008000;
		M32(&FILE_InitStruct.OPTION_BYTES[0x00]) = 0x8F5570AA;
		M32(&FILE_InitStruct.OPTION_BYTES[0x0C]) = 0xF0000FFF;
		break;
	}
	_tcscpy_s((TCHAR*)(CHIP_InitStruct.VENDOR), 0x20, _T("Puya Semiconductor"));
	
	CHIP_InitStruct.FLASH_ADDR = 0x08000000;	
	CHIP_InitStruct.RAM_ADDR = 0x20000000;
	CHIP_InitStruct.SWD_SUPPORT = 1;
	CHIP_InitStruct.ISP_SUPPORT = 1;
	CHIP_InitStruct.CRC = GetCrc16((const BYTE*)(&CHIP_InitStruct.VENDOR), 0x400);

	FILE_InitStruct.BASE_ADDR = CHIP_InitStruct.FLASH_ADDR;
}

#define MAX_MEMORY_SIZE (384*0x400)

// CPY32DfuToolDlg dialog
CPY32DfuToolDlg::CPY32DfuToolDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_PY32DFUTOOL_DIALOG, pParent)
	, m_pDevice(NULL)
	, m_nRadioErase(0)
	, m_wPID(0)
	, m_dwUsbPort(0)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);	

	SetStructData(0x0448);
	//FILE_InitStruct.ID = (CTime::GetCurrentTime().GetTime() & 0xFFFFFFFF);
	FILE_InitStruct.PRO_MODE = PRO_ISP;
	FILE_InitStruct.PRO_SPEED = 1000000;
	FILE_InitStruct.BAUD_RATE = 115200;
	FILE_InitStruct.ERASE_MODE = 2;
	FILE_InitStruct.PROGRAM_FLASH = 1;
	FILE_InitStruct.VERIFY_FLASH = 1;
	FILE_InitStruct.DONE_OPERATE = 0;
	FILE_InitStruct.CODE_SIZE = 0x00000000;

	m_pucProgramMemory = new BYTE[MAX_MEMORY_SIZE];
	m_pucTargetMemory = new BYTE[MAX_MEMORY_SIZE];
	
	memset(m_pucProgramMemory, 0xFF, MAX_MEMORY_SIZE);
	memset(m_pucTargetMemory, 0xFF, MAX_MEMORY_SIZE);

	TRACE(_T("sizeof(FILE_InitStruct) = 0x%04X, sizeof(CHIP_InitStruct) = 0x%04X.\n"), sizeof(FILE_InitStruct), sizeof(CHIP_InitStruct));
}

CPY32DfuToolDlg::~CPY32DfuToolDlg()
{
	delete[] m_pucProgramMemory;
	delete[] m_pucTargetMemory;
}

void CPY32DfuToolDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_PROGRESS, m_XProgressCtrl);
	DDX_Control(pDX, IDC_EDIT_LOG, m_EditLog);
	DDX_Radio(pDX, IDC_RADIO_DONOT_ERASE, m_nRadioErase);
	DDX_Control(pDX, IDC_COMBO_DFU_DEVICE, m_ComboBoxDfuDevice);
	DDX_Control(pDX, IDC_COMBO_APP_ADDR, m_ComboBoxAppAddr);
}

BEGIN_MESSAGE_MAP(CPY32DfuToolDlg, CDialogEx)
	ON_WM_DEVICECHANGE()
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_CHECK_PROGRAM, &CPY32DfuToolDlg::OnBnClickedCheckProgram)
	ON_BN_CLICKED(IDC_CHECK_VERIFY, &CPY32DfuToolDlg::OnBnClickedCheckVerify)
	ON_BN_CLICKED(IDC_CHECK_OPTION_BYTES, &CPY32DfuToolDlg::OnBnClickedCheckProgramOptionBytes)
	ON_BN_CLICKED(IDC_CHECK_RUN_APP, &CPY32DfuToolDlg::OnBnClickedCheckRunApp)
	ON_BN_CLICKED(IDC_BUTTON_DNLOAD_OPEN, &CPY32DfuToolDlg::OnBnClickedButtonDnloadOpen)
	ON_BN_CLICKED(IDC_BUTTON_RUN_APP, &CPY32DfuToolDlg::OnBnClickedButtonRunApp)
	ON_BN_CLICKED(IDC_BUTTON_UPLOAD, &CPY32DfuToolDlg::OnBnClickedButtonUpload)
	ON_BN_CLICKED(IDC_BUTTON_DNLOAD, &CPY32DfuToolDlg::OnBnClickedButtonDnload)
	ON_CBN_SELCHANGE(IDC_COMBO_DFU_DEVICE, &CPY32DfuToolDlg::OnCbnSelchangeComboDfuDevice)
END_MESSAGE_MAP()


// CPY32DfuToolDlg message handlers

BOOL CPY32DfuToolDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	m_Font.CreatePointFont(100, _T("Consolas"));
	GetDlgItem(IDC_EDIT_LOG)->SetFont(&m_Font);
	GetDlgItem(IDC_COMBO_APP_ADDR)->SetFont(&m_Font);

	m_nRadioErase = FILE_InitStruct.ERASE_MODE;

	((CButton*)GetDlgItem(IDC_CHECK_PROGRAM))->SetCheck(FILE_InitStruct.PROGRAM_FLASH);
	((CButton*)GetDlgItem(IDC_CHECK_VERIFY))->SetCheck(FILE_InitStruct.VERIFY_FLASH);
	((CButton*)GetDlgItem(IDC_CHECK_PROGRAM_OPTION_BYTES))->SetCheck(FILE_InitStruct.PROGRAM_OPTION);
	((CButton*)GetDlgItem(IDC_CHECK_RUN_APP))->SetCheck(FILE_InitStruct.DONE_OPERATE);

	OnDeviceChange(0, 0);

	UpdateData(FALSE);

	if (PathFileExists(AfxGetApp()->m_lpCmdLine))
	{
		m_bExitApp = TRUE;
		OpenFile(AfxGetApp()->m_lpCmdLine);
		OnBnClickedButtonDnload();
	}
	else
	{
		m_bExitApp = FALSE;
		//OpenFile(AfxGetApp()->GetProfileString(_T("Settings"), _T("FileName")));
	}

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CPY32DfuToolDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CPY32DfuToolDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CPY32DfuToolDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

#define MAX_MCU_SUPPORT 2

const uint16_t MCU_PID[MAX_MCU_SUPPORT] = { 0x0448, 0x0413 };
const CString MCU_STR[MAX_MCU_SUPPORT] = { _T("PY32F072"), _T("PY32F403") };

BOOL CPY32DfuToolDlg::OnDeviceChange(UINT /*nEventType*/, DWORD_PTR /*dwData*/)
{
	CString csDevice;
	CPuyaDevice PuyaDevice;
	int dev_find_cnt, nIndex = 0;

	int nLastUsbPort = AfxGetApp()->GetProfileInt(_T("Settings"), _T("UsbPort"), 0);

	m_ComboBoxDfuDevice.ResetContent();

	int nSigIndex = 0;
	for (int i = 0; i < MAX_MCU_SUPPORT; i++)
	{
		nSigIndex = 0;
		dev_find_cnt = PuyaDevice.usb_get_device_list(0xFFFF, MCU_PID[i]);
		while (dev_find_cnt--)
		{
			csDevice = MCU_STR[i];
			csDevice.AppendFormat(_T(" - ARM Device in DFU Mode(USB%d)"), nSigIndex++);
			m_ComboBoxDfuDevice.InsertString(nIndex++, csDevice);
		}
	}

	if (nIndex > 0)
	{
		m_ComboBoxDfuDevice.SetCurSel(min(nIndex - 1, nLastUsbPort));
		OnCbnSelchangeComboDfuDevice();
	}

	EnableCtrl(nIndex > 0);

	return TRUE;
}

void CPY32DfuToolDlg::EnableCtrl(BOOL bEnable)
{
	GetDlgItem(IDC_COMBO_DFU_DEVICE)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_DNLOAD_OPEN)->EnableWindow(bEnable);
	GetDlgItem(IDC_RADIO_ERASE_FULL_CHIP)->EnableWindow(bEnable);
	GetDlgItem(IDC_RADIO_ERASE_SECTORS)->EnableWindow(bEnable);
	GetDlgItem(IDC_RADIO_DONOT_ERASE)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_PROGRAM)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_VERIFY)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_PROGRAM_OPTION_BYTES)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_RUN_APP)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_RUN_APP)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_UPLOAD)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_DNLOAD)->EnableWindow(bEnable);
}


void CPY32DfuToolDlg::OnBnClickedCheckProgram()
{
	// TODO: 在此添加控件通知处理程序代码
	FILE_InitStruct.PROGRAM_FLASH = ((CButton*)GetDlgItem(IDC_CHECK_PROGRAM))->GetCheck() ? 1 : 0;
}


void CPY32DfuToolDlg::OnBnClickedCheckVerify()
{
	// TODO: 在此添加控件通知处理程序代码
	FILE_InitStruct.VERIFY_FLASH = ((CButton*)GetDlgItem(IDC_CHECK_VERIFY))->GetCheck() ? 1 : 0;
}


void CPY32DfuToolDlg::OnBnClickedCheckProgramOptionBytes()
{
	// TODO: 在此添加控件通知处理程序代码
	FILE_InitStruct.PROGRAM_OPTION = ((CButton*)GetDlgItem(IDC_CHECK_PROGRAM_OPTION_BYTES))->GetCheck() ? 1 : 0;
	if (FILE_InitStruct.PROGRAM_OPTION) {
		COptionBytesDlg dlg;
		dlg.m_pucOptionBytes = FILE_InitStruct.OPTION_BYTES;
		dlg.m_wPID = m_wPID;
		dlg.DoModal();
	}
}


void CPY32DfuToolDlg::OnBnClickedCheckRunApp()
{
	// TODO: 在此添加控件通知处理程序代码
	FILE_InitStruct.DONE_OPERATE = ((CButton*)GetDlgItem(IDC_CHECK_RUN_APP))->GetCheck() ? 1 : 0;
}

void CPY32DfuToolDlg::OnBnClickedButtonDnloadOpen()
{
	// TODO: 在此添加控件通知处理程序代码
	CFileDialog FileDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Hex/Bin Files(*.hex;*.bin)|*.hex;*.bin||"), NULL);

	if (IDOK == FileDialog.DoModal())
	{
		OpenFile(FileDialog.GetPathName());		
	}
}

BOOL CPY32DfuToolDlg::OpenFile(LPCTSTR lpszPathName)
{
	DWORD dwAddr;

	memset(m_pucProgramMemory, 0xFF, MAX_MEMORY_SIZE);
	FILE_InitStruct.BASE_ADDR = 0x00000000;
	FILE_InitStruct.CODE_SIZE = 0x00000000;	

	CMemoryFile MemoryFile;
	if (!MemoryFile.OpenMemoryFile(lpszPathName, m_pucProgramMemory, FILE_InitStruct.BASE_ADDR, FILE_InitStruct.CODE_SIZE))
	{
		UpdateStatus(_T("Open %s fail."), lpszPathName);
		return FALSE;
	}	

	if (0x00000000 == FILE_InitStruct.BASE_ADDR) {
		CSetAddrSizeDlg dlg;

		FILE_InitStruct.BASE_ADDR = 0x08000000;

		dlg.m_dwAddr = FILE_InitStruct.BASE_ADDR;
		dlg.m_dwSize = FILE_InitStruct.CODE_SIZE;

		if (IDOK == dlg.DoModal())
		{
			FILE_InitStruct.BASE_ADDR = dlg.m_dwAddr;
			FILE_InitStruct.CODE_SIZE = dlg.m_dwSize;
		}
	}

	FILE_InitStruct.CODE_SIZE = (FILE_InitStruct.CODE_SIZE + CHIP_InitStruct.SECTOR_SIZE - 1) & ~(CHIP_InitStruct.SECTOR_SIZE - 1);

	dwAddr = 0x00000000;

	while (dwAddr < CHIP_InitStruct.FLASH_SIZE)
	{
		if (0xFFFFFFFF != M32(m_pucProgramMemory + dwAddr))
		{
			FILE_InitStruct.DATA_ADDR = dwAddr;
			break;
		}
		dwAddr += 4;
	}	

	FILE_InitStruct.FLASH_CHECKSUM = GetCheckSum(m_pucProgramMemory + FILE_InitStruct.DATA_ADDR, FILE_InitStruct.CODE_SIZE);
	FILE_InitStruct.FLASH_CRC = GetCrc16(m_pucProgramMemory + FILE_InitStruct.DATA_ADDR, FILE_InitStruct.CODE_SIZE);

	GetDlgItem(IDC_EDIT_DNLOAD_FILE)->SetWindowText(lpszPathName);

	UpdateStatus(_T("Application addresss 0x%08X, checksum 0x%08X."), FILE_InitStruct.BASE_ADDR + FILE_InitStruct.DATA_ADDR, FILE_InitStruct.FLASH_CHECKSUM);

	AfxGetApp()->WriteProfileString(_T("Settings"), _T("FileName"), lpszPathName);

	return TRUE;
}

void CPY32DfuToolDlg::UpdateStatus(const TCHAR* szFormat, ...)
{
	TCHAR szContent[1024] = { 0 };

	va_list arglist;
	va_start(arglist, szFormat);
	_vsntprintf_s(szContent, 1024, szFormat, arglist);
	va_end(arglist);

	TRACE(_T("%s\n"), szContent);

	m_EditLog.SetSel(m_EditLog.GetWindowTextLength(), -1);

	m_EditLog.ReplaceSel(szContent);
	m_EditLog.ReplaceSel(_T("\r\n"));
}

UINT CPY32DfuToolDlg::ThreadProc(LPVOID lParam)
{
	CPY32DfuToolDlg* pThis = (CPY32DfuToolDlg*)lParam;
	pThis->ThreadFunc();
	return 0;
}

void CPY32DfuToolDlg::ThreadFunc()
{
	uint32_t nErrCode = ERROR_SUCCESS;

	EnableCtrl(FALSE);

	FILE_InitStruct.PRO_MODE = PRO_ISP;

	m_EditLog.SetWindowText(_T(""));
	m_XProgressCtrl.SetBarBkColor(RGB(235, 235, 235));
	m_XProgressCtrl.SetWindowText(_T(""));
	m_XProgressCtrl.Invalidate();
	UpdateStatus(_T("Start %s at %s"), FUNC_TEXT[m_eThreadFuncID], CTime::GetCurrentTime().Format(_T("%H:%M:%S")));

	nErrCode = TargetConnect();
	if (ERROR_SUCCESS != nErrCode) {
		goto Exit_ThreadFunc;
	}

	switch (m_eThreadFuncID)
	{
	case ID_TargetConnect:
		nErrCode = TargetConnect();
		break;
	case ID_TargetDisconnect:
		nErrCode = TargetDisconnect();
		break;
	case ID_TargetDownload:
		nErrCode = TargetDownload();
		break;
	case ID_TargetEraseFullChip:
		nErrCode = TargetEraseFullChip();
		break;
	case ID_TargetEraseSectors:
		nErrCode = TargetEraseSectors();
		break;
	case ID_TargetBlankCheck:
		nErrCode = TargetBlankCheck();
		break;
	case ID_TargetProgram:
		nErrCode = TargetProgram();
		break;
	case ID_TargetVerify:
		nErrCode = TargetVerify();
		break;
	case ID_TargetReadData:
		nErrCode = TargetReadData();
		break;
	case ID_TargetRunApp:
		nErrCode = TargetRunApp();
		//TargetDisconnect();
		break;
	case ID_TargetProgramOptionBytes:
		nErrCode = TargetProgramOptionBytes();
		break;
	}

Exit_ThreadFunc:
	TargetDisconnect();

	switch (nErrCode)
	{
	case ERROR_SUCCESS:
		m_XProgressCtrl.SetBarBkColor(RGB(0, 155, 0));
		m_XProgressCtrl.SetWindowText(_T("PASS"));
		break;
	default:
		m_XProgressCtrl.SetBarBkColor(RGB(255, 0, 0));
		m_XProgressCtrl.SetWindowText(error_message[nErrCode]);
		UpdateStatus(error_message[nErrCode]);
		UpdateStatus(_T("Error: %s failed."), FUNC_TEXT[m_eThreadFuncID]);		
		break;
	}	

	m_XProgressCtrl.SetPos(0);	
	m_XProgressCtrl.Invalidate();

	EnableCtrl(TRUE);

	UpdateStatus(_T("%s finished at %s"), FUNC_TEXT[m_eThreadFuncID], CTime::GetCurrentTime().Format(_T("%H:%M:%S")));

	if ((ERROR_SUCCESS == nErrCode) && m_bExitApp)
	{
		PostMessage(WM_CLOSE, 0, 0);
		return;
	}
}

uint32_t CPY32DfuToolDlg::TargetDownload()
{
	uint32_t nErrCode = ERROR_SUCCESS;

	switch (FILE_InitStruct.ERASE_MODE)
	{
	case 1:
		nErrCode = TargetEraseFullChip();
		break;
	case 2:
		nErrCode = TargetEraseSectors();
		break;
	}
	if (ERROR_SUCCESS != nErrCode) {
		return nErrCode;
	}

	if (FILE_InitStruct.PROGRAM_FLASH) {
		nErrCode = TargetProgram();
		if (ERROR_SUCCESS != nErrCode) {
			return nErrCode;
		}
	}

	if (FILE_InitStruct.VERIFY_FLASH) {
		nErrCode = TargetVerify();
		if (ERROR_SUCCESS != nErrCode) {
			return nErrCode;
		}
	}

	if (FILE_InitStruct.PROGRAM_OPTION) {
		nErrCode = TargetProgramOptionBytes();
		if (ERROR_SUCCESS != nErrCode) {
			return nErrCode;
		}
	}

	if (FILE_InitStruct.DONE_OPERATE) {
		nErrCode = TargetRunApp();
		if (ERROR_SUCCESS != nErrCode) {
			return nErrCode;
		}
	}

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetConnect()
{
	uint32_t nErrCode = ERROR_SUCCESS;

	m_pDevice = new CPuyaDfu;
	nErrCode = m_pDevice->Init(m_dwUsbPort, m_wPID);

	if (ERROR_SUCCESS != nErrCode) {
		return nErrCode;
	}

	AfxGetApp()->WriteProfileInt(_T("Settings"), _T("UsbPort"), m_ComboBoxDfuDevice.GetCurSel());

	nErrCode = TargetReadMcuInfo();

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetReadMcuInfo()
{
	BYTE ucData[0x400];
	CString csText(_T(""));
	DWORD dwFlashSize, dwSramSize;

	if (ERROR_SUCCESS != m_pDevice->ReadMemory(CHIP_InitStruct.OPTION_ADDR, ucData, CHIP_InitStruct.OPTION_SIZE)) {
		return ERROR_GET_OPTION_BYTES;
	}
	UpdateStatus(_T("Getting option bytes successfully!"));
	csText.Empty();
	for (DWORD i = 0; i < CHIP_InitStruct.OPTION_SIZE; i++) {
		if (i && (0 == i % 0x10)) {
			csText.AppendFormat(_T("\r\n"));
		}
		csText.AppendFormat(_T("%02X "), ucData[i]);
	}
	UpdateStatus(csText);

	if (ERROR_SUCCESS != m_pDevice->ReadMemory(CHIP_InitStruct.FLASHSIZE_ADDR, ucData, 0x04))
	{
		return ERROR_GET_FLASH_SRAM_SIZE;
	}
	dwFlashSize = CHIP_InitStruct.FLASH_SIZE;
	dwSramSize = CHIP_InitStruct.RAM_SIZE;

	switch (m_wPID)
	{
	case 0x0440:
		dwFlashSize = (((ucData[0] & 0x07) >> 0) + 1) * 8 * 0x400;
		dwSramSize = (((ucData[0] & 0x30) >> 4) + 1) * 2 * 0x400;
		break;
	case 0x0063:
	case 0x0448:
		dwFlashSize = (((ucData[0] & 0x03) >> 0) + 1) * 32 * 0x400;
		dwSramSize = (((ucData[0] & 0x0C) >> 2) + 1) * 4 * 0x400;
		break;
	case 0x0100:
	case 0x0413:
		dwFlashSize = (((ucData[0] & 0x1F) >> 0) + 1) * 16 * 0x400;
		dwSramSize = (((ucData[0] & 0xE0) >> 5) + 1) * 8 * 0x400;
		break;
	}

	CHIP_InitStruct.FLASH_SIZE = min(dwFlashSize, CHIP_InitStruct.FLASH_SIZE);
	CHIP_InitStruct.RAM_SIZE = min(dwSramSize, CHIP_InitStruct.RAM_SIZE);
	UpdateStatus(_T("Getting flash and sram size successfully!\r\nFlash size %dKB, Sram size %dKB."), CHIP_InitStruct.FLASH_SIZE / 0x400, CHIP_InitStruct.RAM_SIZE / 0x400);

	if (ERROR_SUCCESS != m_pDevice->ReadMemory(CHIP_InitStruct.UID_ADDR, ucData, 12/*CHIP_InitStruct.UID_SIZE*/))
	{
		return ERROR_GET_UID;
	}
	UpdateStatus(_T("Getting UID successfully!"));
	csText.Empty();
	for (int i = 0; i < 12/*CHIP_InitStruct.UID_SIZE*/; i++) {
		//if (i && (0 == i % 0x10)) {
		//	csText.AppendFormat(_T("\r\n"));
		//}
		csText.AppendFormat(_T("%02X "), ucData[i]);
	}
	UpdateStatus(csText);

	return ERROR_SUCCESS;
}

uint32_t CPY32DfuToolDlg::TargetDisconnect()
{
	uint32_t nErrCode = ERROR_SUCCESS;
	
	nErrCode = m_pDevice->Uninit();

	delete m_pDevice;

	m_pDevice = NULL;

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetEraseFullChip()
{
	uint32_t nErrCode = ERROR_SUCCESS;

	m_XProgressCtrl.SetWindowText(_T("Erasing..."));

	nErrCode = m_pDevice->EraseChip();
	if (ERROR_SUCCESS != nErrCode) {
		UpdateStatus(_T("EraseChip Fail."));
	}
	else {
		UpdateStatus(_T("EraseChip Done."));
	}
	m_XProgressCtrl.SetWindowText(_T(""));

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetEraseSectors()
{
	uint8_t* data;
	uint32_t nErrCode = ERROR_SUCCESS;
	uint32_t addr, size = 0;

	data = new uint8_t[2 * (FILE_InitStruct.CODE_SIZE / CHIP_InitStruct.SECTOR_SIZE)];

	m_XProgressCtrl.SetWindowText(_T("Erasing..."));

	addr = FILE_InitStruct.DATA_ADDR;
	while ((addr - FILE_InitStruct.DATA_ADDR) < FILE_InitStruct.CODE_SIZE)
	{
		for (uint32_t j = 0; j < CHIP_InitStruct.SECTOR_SIZE; j++)
		{
			if (0xFF != m_pucProgramMemory[addr + j])
			{
				data[2 * size + 0] = ((addr / CHIP_InitStruct.SECTOR_SIZE) >> 8) & 0xFF;
				data[2 * size + 1] = ((addr / CHIP_InitStruct.SECTOR_SIZE) >> 0) & 0xFF;
				size++;
				break;
			}
		}
		addr += CHIP_InitStruct.SECTOR_SIZE;
	}
	for (uint32_t i = 0; i < size / 0x10; i++) {
		addr = i * CHIP_InitStruct.SECTOR_SIZE * 0x10;
		nErrCode = m_pDevice->EraseSector(&data[i * 0x10 * 2], 0x10);
		if (ERROR_SUCCESS != nErrCode) {
			break;
		}
	}
	if (size % 0x10) {
		nErrCode = m_pDevice->EraseSector(&data[(size / 0x10) * 0x10 * 2], size % 0x10);
	}

	if (ERROR_SUCCESS != nErrCode) {
		UpdateStatus(_T("EraseSector Fail at: %08XH."), addr);
	}
	else {
		UpdateStatus(_T("EraseSector Done."));
	}

	m_XProgressCtrl.SetWindowText(_T(""));

	delete[] data;

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetBlankCheck()
{
	CString csText;
	uint32_t nErrCode = ERROR_SUCCESS;
	uint32_t dwAddr = FILE_InitStruct.DATA_ADDR;

	m_XProgressCtrl.SetRange(0, (short)(FILE_InitStruct.CODE_SIZE / CHIP_InitStruct.PAGE_SIZE));

	while ((dwAddr - FILE_InitStruct.DATA_ADDR) < FILE_InitStruct.CODE_SIZE)
	{
		m_XProgressCtrl.SetPos(dwAddr / CHIP_InitStruct.PAGE_SIZE);
		csText.Format(_T("BlankCheck: %08XH"), dwAddr);
		m_XProgressCtrl.SetWindowText(csText);

		nErrCode = m_pDevice->ReadMemory(FILE_InitStruct.BASE_ADDR + dwAddr, m_pucTargetMemory + dwAddr, CHIP_InitStruct.PAGE_SIZE);
		if (ERROR_SUCCESS != nErrCode) {
			UpdateStatus(_T("Read Failed at: %08XH."), FILE_InitStruct.BASE_ADDR + dwAddr);
			break;
		}
		for (uint32_t j = 0; j < CHIP_InitStruct.PAGE_SIZE; j++) {
			if (0xFF != m_pucTargetMemory[dwAddr + j]) {
				UpdateStatus(_T("Contents mismatch at: %08XH (Flash=%02XH Requitred=%02XH) !"),
					FILE_InitStruct.BASE_ADDR + dwAddr + j, m_pucTargetMemory[dwAddr + j], 0xFF);
				return 2;
			}
		}
		dwAddr += CHIP_InitStruct.PAGE_SIZE;
	}

	UpdateStatus(_T("BlankCheck OK."));

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetProgram()
{
	CString csText;
	uint32_t nErrCode = ERROR_SUCCESS;
	uint32_t dwAddr = FILE_InitStruct.DATA_ADDR;

	m_XProgressCtrl.SetRange(0, (short)(FILE_InitStruct.CODE_SIZE / CHIP_InitStruct.PAGE_SIZE));

	while ((dwAddr - FILE_InitStruct.DATA_ADDR) < FILE_InitStruct.CODE_SIZE)
	{
		m_XProgressCtrl.SetPos(dwAddr / CHIP_InitStruct.PAGE_SIZE);
		csText.Format(_T("Program: %08XH"), FILE_InitStruct.BASE_ADDR + dwAddr);
		m_XProgressCtrl.SetWindowText(csText);
		for (uint32_t j = 0; j < CHIP_InitStruct.PAGE_SIZE; j++)
		{
			if (0xFF != m_pucProgramMemory[dwAddr + j])
			{
				nErrCode = m_pDevice->WriteMemory(FILE_InitStruct.BASE_ADDR + dwAddr,
					m_pucProgramMemory + dwAddr, CHIP_InitStruct.PAGE_SIZE);
				if (ERROR_SUCCESS != nErrCode) {
					UpdateStatus(_T("Programming Failed at: %08XH."), FILE_InitStruct.BASE_ADDR + dwAddr);
					return nErrCode;
				}

				break;
			}
		}
		dwAddr += CHIP_InitStruct.PAGE_SIZE;
	}

	m_XProgressCtrl.SetPos(FILE_InitStruct.CODE_SIZE / CHIP_InitStruct.PAGE_SIZE);

	UpdateStatus(_T("Programming Done."));

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetVerify()
{
	CString csText;
	uint32_t nErrCode = ERROR_SUCCESS;
	uint32_t dwAddr = FILE_InitStruct.DATA_ADDR;

	m_XProgressCtrl.SetRange(0, (short)(FILE_InitStruct.CODE_SIZE / CHIP_InitStruct.PAGE_SIZE));

	while ((dwAddr - FILE_InitStruct.DATA_ADDR) < FILE_InitStruct.CODE_SIZE)
	{
		m_XProgressCtrl.SetPos(dwAddr / CHIP_InitStruct.PAGE_SIZE);
		csText.Format(_T("Verify: %08XH"), FILE_InitStruct.BASE_ADDR + dwAddr);
		m_XProgressCtrl.SetWindowText(csText);
		for (uint32_t j = 0; j < CHIP_InitStruct.PAGE_SIZE; j++)
		{
			if (0xFF != m_pucProgramMemory[dwAddr + j])
			{
				nErrCode = m_pDevice->ReadMemory(FILE_InitStruct.BASE_ADDR + dwAddr,
					m_pucTargetMemory + dwAddr, CHIP_InitStruct.PAGE_SIZE);
				if (ERROR_SUCCESS != nErrCode) {
					UpdateStatus(_T("Read Failed at: %08XH."), FILE_InitStruct.BASE_ADDR + dwAddr);
					return nErrCode;
				}
				for (uint32_t k = 0; k < CHIP_InitStruct.PAGE_SIZE; k++) {
					if (m_pucTargetMemory[dwAddr + k] != m_pucProgramMemory[dwAddr + k]) {
						UpdateStatus(_T("Contents mismatch at: %08XH (Flash=%02XH Requitred=%02XH) !"),
							FILE_InitStruct.BASE_ADDR + dwAddr + k, m_pucTargetMemory[dwAddr + k], m_pucProgramMemory[dwAddr + k]);
						return 2;
					}
				}

				break;
			}
		}
		dwAddr += CHIP_InitStruct.PAGE_SIZE;
	}
	m_XProgressCtrl.SetPos(FILE_InitStruct.CODE_SIZE / CHIP_InitStruct.PAGE_SIZE);

	UpdateStatus(_T("Verify OK."));

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetReadData()
{
	CString csText;
	uint32_t nErrCode = ERROR_SUCCESS;
	uint32_t dwAddr = 0;
	CSetAddrSizeDlg dlg;

	dlg.m_dwAddr = CHIP_InitStruct.FLASH_ADDR;
	dlg.m_dwSize = CHIP_InitStruct.FLASH_SIZE;

	dlg.DoModal();

	m_XProgressCtrl.SetRange(0, (short)(dlg.m_dwSize / CHIP_InitStruct.PAGE_SIZE));
	while ((dwAddr / CHIP_InitStruct.PAGE_SIZE) < (dlg.m_dwSize / CHIP_InitStruct.PAGE_SIZE))
	{
		m_XProgressCtrl.SetPos(dwAddr / CHIP_InitStruct.PAGE_SIZE);
		csText.Format(_T("Read: %08XH"), dlg.m_dwAddr + dwAddr);
		m_XProgressCtrl.SetWindowText(csText);

		nErrCode = m_pDevice->ReadMemory(dlg.m_dwAddr + dwAddr, m_pucTargetMemory + dwAddr, CHIP_InitStruct.PAGE_SIZE);
		if (ERROR_SUCCESS != nErrCode) {
			UpdateStatus(_T("Read Failed at: %08XH."), dlg.m_dwAddr + dwAddr);
			return nErrCode;
		}

		dwAddr += CHIP_InitStruct.PAGE_SIZE;
	}

	if (dlg.m_dwSize % CHIP_InitStruct.PAGE_SIZE)
	{
		nErrCode = m_pDevice->ReadMemory(dlg.m_dwAddr + dwAddr, m_pucTargetMemory + dwAddr, dlg.m_dwSize % CHIP_InitStruct.PAGE_SIZE);
		if (ERROR_SUCCESS != nErrCode) {
			UpdateStatus(_T("Read Failed at: %08XH."), dlg.m_dwAddr + dwAddr);
			return nErrCode;
		}
	}

	UpdateStatus(_T("Read Done."));

	CMemoryFile MemoryFile;
	MemoryFile.SaveMemoryFileEx(m_pucTargetMemory, dlg.m_dwAddr, dlg.m_dwSize);

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetRunApp()
{
	uint32_t nErrCode = ERROR_SUCCESS;

	nErrCode = m_pDevice->Go(FILE_InitStruct.BASE_ADDR + FILE_InitStruct.DATA_ADDR);
	if (ERROR_SUCCESS != nErrCode) {
		UpdateStatus(_T("Run App Fail."));
	}
	else {
		UpdateStatus(_T("Application running ..."));
	}

	return nErrCode;
}

uint32_t CPY32DfuToolDlg::TargetProgramOptionBytes()
{
	CString csText;
	uint8_t ucData[0x80];
	uint32_t nErrCode = ERROR_SUCCESS;

	if (ERROR_SUCCESS != m_pDevice->WriteMemory(CHIP_InitStruct.OPTION_ADDR, FILE_InitStruct.OPTION_BYTES, CHIP_InitStruct.OPTION_SIZE)) {
		UpdateStatus(_T("Program option bytes Fail."));
	}
	else {
		UpdateStatus(_T("Program option bytes Done."));
	}

	if (RDP_LEVEL_0 != FILE_InitStruct.OPTION_BYTES[0x00])
	{
		return ERROR_SUCCESS;
	}

	m_pDevice->Uninit();

	Sleep(500);

	nErrCode = m_pDevice->Init(m_dwUsbPort, m_wPID);
	if (ERROR_SUCCESS != nErrCode) {
		return nErrCode;
	}

	if (ERROR_SUCCESS != m_pDevice->ReadMemory(CHIP_InitStruct.OPTION_ADDR, ucData, CHIP_InitStruct.OPTION_SIZE)) {
		UpdateStatus(_T("Read option bytes Error."));
		return ERROR_GET_OPTION_BYTES;
	}

	UpdateStatus(_T("Getting option bytes successfully!"));
	csText.Empty();
	for (DWORD i = 0; i < CHIP_InitStruct.OPTION_SIZE; i++) {
		if (i && (0 == i % 0x10)) {
			csText.AppendFormat(_T("\r\n"));
		}
		csText.AppendFormat(_T("%02X "), ucData[i]);
	}
	UpdateStatus(csText);

	switch (m_wPID)
	{
	case 0x0063:
	case 0x0448:
		if ( (M32(&FILE_InitStruct.OPTION_BYTES[0x00]) != M32(&ucData[0x00]))
		  || (M32(&FILE_InitStruct.OPTION_BYTES[0x08]) != M32(&ucData[0x08]))
		  || (M32(&FILE_InitStruct.OPTION_BYTES[0x18]) != M32(&ucData[0x18])) )
		{
			UpdateStatus(_T("Verify option bytes Error."));
			return ERROR_GET_OPTION_BYTES;
		}
		break;
	case 0x0100:
	case 0x0413:
		if ( (M32(&FILE_InitStruct.OPTION_BYTES[0x00]) != M32(&ucData[0x00]))
		  || (M32(&FILE_InitStruct.OPTION_BYTES[0x0C]) != M32(&ucData[0x0C])) )
		{
			UpdateStatus(_T("Verify option bytes Error."));
			return ERROR_GET_OPTION_BYTES;
		}
		break;
	}

	UpdateStatus(_T("Verify option bytes successfully."));

	return ERROR_SUCCESS;
}

void CPY32DfuToolDlg::OnBnClickedButtonRunApp()
{
	// TODO: 在此添加控件通知处理程序代码
	m_eThreadFuncID = ID_TargetRunApp;
	AfxBeginThread(ThreadProc, this);
}

void CPY32DfuToolDlg::OnBnClickedButtonUpload()
{
	// TODO: 在此添加控件通知处理程序代码
	m_eThreadFuncID = ID_TargetReadData;
	AfxBeginThread(ThreadProc, this);
}

void CPY32DfuToolDlg::OnBnClickedButtonDnload()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData();

	FILE_InitStruct.ERASE_MODE = m_nRadioErase;

	m_eThreadFuncID = ID_TargetDownload;
	AfxBeginThread(ThreadProc, this);
}


void CPY32DfuToolDlg::OnCbnSelchangeComboDfuDevice()
{
	// TODO: 在此添加控件通知处理程序代码
	CString csWindowsText, csFindText;

	m_ComboBoxDfuDevice.GetWindowText(csWindowsText);

	for (int i = 0;i < MAX_MCU_SUPPORT;i++)
	{
		if (-1 != csWindowsText.Find(MCU_STR[i], 0))
		{
			SetStructData(MCU_PID[i]);
			break;
		}
	}

	for (int i = 0; i < m_ComboBoxDfuDevice.GetCount(); i++)
	{
		csFindText.Format(_T("USB%d"), i);
		if (-1 != csWindowsText.Find(csFindText, 0))
		{
			m_dwUsbPort = i;
			break;
		}
	}
}